package dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.LinkedList;
import java.util.List;
import blogLib.itf.IComentario;
import java.sql.Types;
import java.util.Calendar;
import model.Comentario;
import utils.UtilString;

/**
 * Classe de tradução de dados de objeto para modelo relacional.
 * @author Alan Alves Oliveira
 */
public class ComentarioDAO extends ConexaoBD {
    private Connection conn;

    /**
     * Construtor que gera uma conexão.
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws SQLException
     */
    public ComentarioDAO(String caminho, String nomeBD, String usuario, String senha) throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException {
        this.conn = getConexao(caminho, nomeBD, usuario, senha);
    }

    /**
     * Construtor que recebe uma conexão.
     * @param conn Conexão com banco de dados.
     */
    public ComentarioDAO(Connection conn) {
        this.conn = conn;
    }

    /**
     * Retorna um comentário pelo id.
     * @param id Identificador do comentário a ser retornado.
     * @return Objeto IComentario. Se o comentário não existir, retorna null.
     * @throws SQLException
     */
    public IComentario getComentario(int id) throws SQLException {
        ResultSet rs = null;
        PreparedStatement pst = null;
        IComentario c = null;
        try {
            pst = conn.prepareStatement("SELECT * FROM comentario WHERE id = ?");
            pst.setInt(1, id);
            rs = pst.executeQuery();
            if (rs.next())
                c = getComentarioFromSQL(rs);
            return c;
        } catch (SQLException e) {
            throw new SQLException(e.getMessage());
        } finally {
            pst.close();
            rs.close();
        }
    }

    /**
     * Retorna uma lista de comentários.
     * @return Objeto List com uma lista de comentários. Ordenação decrescente por data de comentário.
     * @throws SQLException
     */
    public List<IComentario> getListaComentario() throws SQLException {
        ResultSet rs = null;
        Statement st = null;
        try {
            st = conn.createStatement();
            rs = st.executeQuery("SELECT * FROM comentario ORDER BY DataComentario DESC");
            return montaLista(rs);
        } catch (SQLException e) {
            throw new SQLException(e.getMessage());
        } finally {
            st.close();
            rs.close();
        }
    }

    /**
     * Retorna uma lista de comentários filtrando pelo artigo ao qual pertencem.
     * @param idArtigo Id do artigo.
     * @return Objeto List com uma lista de comentários. Ordenação decrescente por data de comentário.
     * @throws SQLException
     */
    public List<IComentario> getListaComentario(int idArtigo) throws SQLException {
        ResultSet rs = null;
        PreparedStatement pst = null;
        try {
            pst = conn.prepareStatement("SELECT * FROM comentario WHERE ArtigoId = ? ORDER BY DataComentario DESC");
            pst.setInt(1, idArtigo);
            rs = pst.executeQuery();
            return montaLista(rs);
        } catch (SQLException e) {
            throw new SQLException(e.getMessage());
        } finally {
            pst.close();
            rs.close();
        }
    }

    /**
     * Retorna uma lista de comentários filtrando pelo usuário proprietário.
     * @param loginUsuario Login do usuário.
     * @return Objeto List com uma lista de comentários. Ordenação decrescente por data de comentário.
     * @throws SQLException
     */
    public List<IComentario> getListaComentario(String loginUsuario) throws SQLException {
        ResultSet rs = null;
        PreparedStatement pst = null;
        try {
            pst = conn.prepareStatement("SELECT * FROM comentario WHERE UsuarioLogin = ? ORDER BY DataComentario DESC");
            pst.setString(1, loginUsuario);
            rs = pst.executeQuery();
            return montaLista(rs);
        } catch (SQLException e) {
            throw new SQLException(e.getMessage());
        } finally {
            pst.close();
            rs.close();
        }
    }

    /**
     * Faz a persistência de um comentário no banco de dados.
     * @param c Objeto IComentario.
     * @return Retorna o ID do comentário no banco de dados.
     * @throws SQLException
     */
    public int incluiComentario(IComentario c) throws SQLException {
        Statement st = null;
        ResultSet rs = null;
        String sql = "";
        Calendar dataComentario = null;
        String textoDataComentario = null;
        int codigo = -1;
        try {
            dataComentario = Calendar.getInstance();
            textoDataComentario = dataComentario.get(Calendar.YEAR) + "-" +
                    (dataComentario.get(Calendar.MONTH) + 1) + "-" +
                    dataComentario.get(Calendar.DATE) + " " +
                    dataComentario.get(Calendar.HOUR_OF_DAY) + ":" +
                    dataComentario.get(Calendar.MINUTE) + ":" +
                    dataComentario.get(Calendar.SECOND);
            sql = "INSERT INTO comentario VALUES (" +
                    "0" +
                    ", " + UtilidadeSQL.verificaNulo(c.getIdArtigo(), Types.INTEGER) +
                    ", " + UtilidadeSQL.verificaNulo(c.getLoginUsuario(), Types.VARCHAR) +
                    ", " + UtilidadeSQL.verificaNulo(c.getNomeVisitante(), Types.VARCHAR) +
                    ", " + UtilidadeSQL.verificaNulo(c.getTexto(), Types.VARCHAR) +
                    ", '" + textoDataComentario + "')";
            st = conn.createStatement();
            st.executeUpdate(sql, st.RETURN_GENERATED_KEYS);
            rs = st.getGeneratedKeys();
            if (rs.next())
                codigo = rs.getInt(1);
            return codigo;
        } catch (SQLException e) {
            throw new SQLException(e.getMessage());
        } finally {
            st.close();
        }

    }

    /**
     * Altera um comentário persistido. Somente os atributos nomeVisitante e texto podem ser alterados
     * por este método.
     * @param c Objeto IComentario.
     * @throws SQLException
     */
    public void alteraComentario(IComentario c) throws SQLException {
        PreparedStatement pst = null;
        try {
            pst = conn.prepareStatement("UPDATE comentario SET" +
                " NomeVisitante = ?" +
                ", Texto = ?" +
                " WHERE Id = ?");
            UtilidadeSQL.verificaNulo(c.getNomeVisitante(), Types.VARCHAR, pst, 1);
            UtilidadeSQL.verificaNulo(c.getTexto(), Types.VARCHAR, pst, 2);
            pst.setInt(3, c.getId());
            pst.execute();
        } catch (SQLException e) {
            throw new SQLException(e.getMessage());
        } finally {
            pst.close();
        }
    }

    /**
     * Exclui um comentário persistido.
     * @param id Id do comentário.
     * @return Comentário excluído. Se o comentário não existir, retorna null.
     * @throws SQLException
     */
    public IComentario excluiComentario(int id) throws SQLException {
        PreparedStatement pst = null;
        try {
            IComentario c = this.getComentario(id);
            if (c != null) {
                pst = conn.prepareStatement("DELETE FROM comentario WHERE Id = ?");
                pst.setInt(1, id);
                pst.execute();
            }
            return c;
        } catch (SQLException e) {
            throw new SQLException(e.getMessage());
        } finally {
            pst.close();
        }
    }

    /**
     * Instancia um objeto IComentario a partir do resultado em um ResultSet.
     * @param rs Objeto ResultSet que contém os dados do comentário.
     * @return Objeto IComentario.
     * @throws SQLException
     */
    private IComentario getComentarioFromSQL(ResultSet rs) throws SQLException {
        IComentario c = new Comentario();
        c.setId(rs.getInt("Id"));
        c.setIdArtigo(rs.getInt("ArtigoId"));
        c.setLoginUsuario(UtilString.isnull(rs.getString("UsuarioLogin")));
        c.setNomeVisitante(UtilString.isnull(rs.getString("NomeVisitante")));
        c.setTexto(rs.getString("Texto"));
        Calendar data = Calendar.getInstance();
        Calendar hora = Calendar.getInstance();
        data.setTime(rs.getDate("DataComentario"));
        hora.setTime(rs.getTime("DataComentario"));
        data.add(Calendar.HOUR_OF_DAY, hora.get(Calendar.HOUR_OF_DAY));
        data.add(Calendar.MINUTE, hora.get(Calendar.MINUTE));
        data.add(Calendar.SECOND, hora.get(Calendar.SECOND));
        c.setDataComentario(data);
        return c;
    }

    /**
     * Monta uma lista de comentários com o resultado de um ResultSet.
     * @param rs ResultSet que contém os dados dos comentários.
     * @return Retorna um objeto List com uma lista de objetos IComentario.
     * @throws SQLException
     */
    private List<IComentario> montaLista(ResultSet rs) throws SQLException {
        List<IComentario> l = new LinkedList<IComentario>();
        while (rs.next())
            l.add(getComentarioFromSQL(rs));
        return l;
    }

}